// OneServerMain.cpp

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <vector>
#include <iterator>
#include <algorithm>
#include <Winsock2.h>
#include <Windows.h>

using namespace std;
HANDLE bufferMutex;        // 令其能互斥成功正常通信的信号量句柄
SOCKET sockConn;        // 客户端的套接字
vector <SOCKET> clientSocketGroup;

DWORD WINAPI SendMessageThread(LPVOID IpParameter);
DWORD WINAPI ReceiveMessageThread(LPVOID IpParameter);

int main()
{
    // 加载socket动态链接库(dll)
    WORD wVersionRequested;
    //加载套接字库
    WSADATA wsaData; //初始化网络环境
    wVersionRequested = MAKEWORD( 2, 2 );    // 请求2.2版本的WinSock库
    int err = WSAStartup( wVersionRequested, &wsaData );
    if ( err != 0 )
    {
        return -1;  // 返回值为零的时候是表示成功申请WSAStartup
    }
    if ( LOBYTE( wsaData.wVersion ) != 2 ||    HIBYTE( wsaData.wVersion ) != 2 )   // 检测是否2.2版本的socket库
    {
        WSACleanup( );
        return -1;
    }

    // 创建socket操作，建立流式套接字，返回套接字号sockSrv
    SOCKET sockSrv = socket(AF_INET, SOCK_STREAM, 0);

    //初始化服务器地址族变量
    SOCKADDR_IN addrSrv;
    addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
    //INADDR_ANY就是指定地址为0.0.0.0的地址,这个地址事实上表示不确定地址,或“所有地址”、“任意地址”。
    //比如你的机器有三个ip
    //192.168.1.1
    //202.202.202.202
    //61.1.2.3
    //如果你serv.sin_addr.s_addr=inet_addr("192.168.1.1");
    //然后监听100端口
    //这时其他机器只有connect   192.168.1.1:100才能成功。
    //connect   202.202.202.202:100和connect   61.1.2.3:100都会失败。
    //如果serv.sin_addr.s_addr=htonl(INADDR_ANY);   的话，无论连接哪个ip都可以连上的,只要是往这个端口发送的所有ip都能连上。
    addrSrv.sin_family = AF_INET;   //指定ipv4协议
    addrSrv.sin_port = htons(6000); //主机字节序

    // 绑定套接字
    if(SOCKET_ERROR == bind(sockSrv, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR)))
    {
        return -1;
    }

    // 将套接字设置为监听模式（连接请求），listen()通知TCP服务器准备好接收连接，最大连接数为20
    listen(sockSrv, 20);

    cout << "Server prepared\n";

    // 设置信号量的值
    bufferMutex = CreateSemaphore(NULL, 1, 1, NULL);

    // 建立一个向所有客户端发送信息的线程
    HANDLE sendThread = CreateThread(NULL, 0, SendMessageThread, NULL, 0, NULL);

    while(true)// 不断等待客户端请求的到来
    {
        sockConn = accept(sockSrv, NULL, NULL);
        if (SOCKET_ERROR != sockConn)
        {
            clientSocketGroup.push_back(sockConn);  //若连接成功则将客户端套接字加入clientSocketGroup
        }

        // 建立一个接收指定客户端信息的线程
        HANDLE receiveThread = CreateThread(NULL, 0, ReceiveMessageThread, (LPVOID)sockConn, 0, NULL);

        WaitForSingleObject(bufferMutex, INFINITE);        // P操作（资源未被占用则使用资源）
        if(NULL == receiveThread)
        {
            cout << "CreatThread AnswerThread() failed." << endl;
        }
        else
        {
            cout << "Create Receive Client Thread OK." << endl;
        }
        ReleaseSemaphore(bufferMutex, 1, NULL);        // V操作（资源占用完毕将其释放）
    }

    WaitForSingleObject(sendThread, INFINITE);  // 等待线程结束
    CloseHandle(sendThread);
    CloseHandle(bufferMutex);
    WSACleanup();    // 终止对套接字库的使用
    system("pause");
    return 0;
}


DWORD WINAPI SendMessageThread(LPVOID IpParameter)
{
    while(1)
    {
        string talk;
        getline(cin, talk);
        WaitForSingleObject(bufferMutex, INFINITE);        // P（资源未被占用）

        //若服务器要主动关闭
        if("quit" == talk)
        {
            talk.push_back('\0');
            for(int i = 0; i < clientSocketGroup.size(); ++i)
            {
                send(clientSocketGroup[i], talk.c_str(), talk.size(), 0);    // 发送信息
            }
            ReleaseSemaphore(bufferMutex, 1, NULL);        // V（资源占用完毕）
            exit(0);
        }

        cout << "I Say:(\"quit\"to exit):" << talk << endl;

        for(int i = 0; i < clientSocketGroup.size(); ++i)
        {
            send(clientSocketGroup[i], talk.c_str(), talk.size(), 0);    // 发送信息
        }
        ReleaseSemaphore(bufferMutex, 1, NULL);        // V（资源占用完毕）
    }
    return 0;
}


DWORD WINAPI ReceiveMessageThread(LPVOID IpParameter)
{
    SOCKET ClientSocket=(SOCKET)(LPVOID)IpParameter;
    while(1)
    {
        char recvBuf[300];
        int recv_id = recv(ClientSocket, recvBuf, 200, 0);

        WaitForSingleObject(bufferMutex, INFINITE);        // P操作（资源未被占用）

        if(recv_id == -1)
        {
            vector<SOCKET>::iterator result = find(clientSocketGroup.begin(), clientSocketGroup.end(), ClientSocket);
            clientSocketGroup.erase(result);
            closesocket(ClientSocket);
            ReleaseSemaphore(bufferMutex, 1, NULL);        // V操作（资源占用完毕）
            cout << "Attention: A Client accidentally dropped ..." << endl;
            break;
        }

        //若从客户端收到了"quit"命令则将该客户端套接字从clientSocketGroup中清除并关闭
        if (recvBuf[0] == 'q' && recvBuf[1] == 'u' && recvBuf[2] == 'i' && recvBuf[3] == 't' && recvBuf[4] == '\0')
        {
            vector<SOCKET>::iterator result = find(clientSocketGroup.begin(), clientSocketGroup.end(), ClientSocket);
            clientSocketGroup.erase(result);
            closesocket(ClientSocket);
            ReleaseSemaphore(bufferMutex, 1, NULL);        // V操作（资源占用完毕）
            cout << "Attention: A Client has left ..." << endl;
            break;
        }

        cout << "One Client Says: " << recvBuf << endl;     // 接收信息

        ReleaseSemaphore(bufferMutex, 1, NULL);        // V（资源占用完毕）
    }
    return 0;
}